#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>

#define GPS_PORT "/dev/ttyS0" // 根据实际串口设备进行修改
#define BUFFER_SIZE 256
#define CACHE_SIZE 1024 // 缓存大小

char gps_cache[CACHE_SIZE];
int cache_index = 0;

void setup_serial(int fd) {
    struct termios options;
    tcgetattr(fd, &options);
    options.c_cflag = B9600 | CS8 | CLOCAL | CREAD; // 设置波特率为9600
    options.c_iflag = IGNPAR; // 忽略帧错误
    options.c_oflag = 0;
    options.c_lflag = 0;
    tcflush(fd, TCIFLUSH);
    tcsetattr(fd, TCSANOW, &options);
}

void parse_nmea_sentence(const char *sentence) {
    // 解析NMEA句子
    if (strncmp(sentence, "$GPGGA", 6) == 0) {
        // 处理GGA句子
        char time[10], lat[15], lat_dir[2], lon[15], lon_dir[2], quality[2], num_sats[3], hdop[5], alt[10], alt_unit[2];
        sscanf(sentence, "$GPGGA,%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,]", time, lat, lat_dir, lon, lon_dir, quality, num_sats, hdop, alt, alt_unit);
        printf("GGA Data: Time: %s, Latitude: %s %s, Longitude: %s %s, Quality: %s, Satellites: %s, HDOP: %s, Altitude: %s %s\n",
               time, lat, lat_dir, lon, lon_dir, quality, num_sats, hdop, alt, alt_unit);
    } else if (strncmp(sentence, "$GPRMC", 6) == 0) {
        // 处理RMC句子
        char time[10], status[2], lat[15], lat_dir[2], lon[15], lon_dir[2], speed[10], course[10], date[10];
        sscanf(sentence, "$GPRMC,%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%s", time, status, lat, lat_dir, lon, lon_dir, speed, course, date);
        printf("RMC Data: Time: %s, Status: %s, Latitude: %s %s, Longitude: %s %s, Speed: %s, Course: %s, Date: %s\n",
               time, status, lat, lat_dir, lon, lon_dir, speed, course, date);
    } else if (strncmp(sentence, "$GPGSA", 6) == 0) {
        // 处理GSA句子
        char mode[2], fix_type[2], prn[64], pdop[5], hdop[5], vdop[5];
        char prn_values[12][4]; // 存储最多12个PRN值
        sscanf(sentence, "$GPGSA,%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%s", mode, fix_type, prn_values[0], prn_values[1], prn_values[2], prn_values[3], prn_values[4], prn_values[5], prn_values[6], prn_values[7], pdop, hdop, vdop);
        printf("GSA Data: Mode: %s, Fix Type: %s, PRN: ", mode, fix_type);
        for (int i = 0; i < 12; i++) {
            if (strlen(prn_values[i]) > 0) {
                printf("%s ", prn_values[i]);
            }
        }
        printf(", PDOP: %s, HDOP: %s, VDOP: %s\n", pdop, hdop, vdop);
    } else if (strncmp(sentence, "$GPGLL", 6) == 0) {
        // 处理GLL句子
        char lat[15], lat_dir[2], lon[15], lon_dir[2], status[2];
        sscanf(sentence, "$GPGLL,%[^,],%[^,],%[^,],%[^,],%s", lat, lat_dir, lon, lon_dir, status);
        printf("GLL Data: Latitude: %s %s, Longitude: %s %s, Status: %s\n", lat, lat_dir, lon, lon_dir, status);
    }
    // 可以添加更多的NMEA句子解析
}

void process_gps_data(const char *data) {
    // 处理接收到的GPS数据
    printf("Received GPS Data: %s\n", data);
    parse_nmea_sentence(data); // 解析NMEA句子
}

void read_gps_data(int fd) {
    char buffer[BUFFER_SIZE];
    while (1) {
        int n = read(fd, buffer, sizeof(buffer) - 1);
        if (n > 0) {
            buffer[n] = '\0'; // 确保字符串结束

            // 将数据存入缓存
            for (int i = 0; i < n; i++) {
                if (cache_index < CACHE_SIZE - 1) {
                    gps_cache[cache_index++] = buffer[i];
                }
            }
            gps_cache[cache_index] = '\0'; // 确保缓存字符串结束

            // 检查缓存中是否有完整的GPS数据
            char *newline = strchr(gps_cache, '\n');
            if (newline) {
                *newline = '\0'; // 将第一个换行符替换为字符串结束符
                process_gps_data(gps_cache); // 处理完整的GPS数据
                // 清空缓存
                memmove(gps_cache, newline + 1, cache_index - (newline - gps_cache) - 1);
                cache_index -= (newline - gps_cache) + 1;
            }
        }
        usleep(100000); // 10Hz, 每100ms读取一次
    }
}

int main() {
    int fd = open(GPS_PORT, O_RDWR | O_NOCTTY);
    if (fd == -1) {
        perror("Unable to open GPS port");
        return EXIT_FAILURE;
    }

    setup_serial(fd);
    read_gps_data(fd);

    close(fd);
    return EXIT_SUCCESS;
}
